﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Seagull.Controls;
using Seagull.DAL;
using Seagull.Events;
using Seagull.Generic;
using Seagull.Model;

namespace Seagull.Shell.Views
{
    public partial class ChartView : BaseView
    {
        private readonly FrameSource _frameSource = new FrameSource();
        private readonly ReplayController _replayController;
        private readonly RealtimeController _realtimeController;
        private volatile ViewMode _currentViewMode;

        private bool _isUserChanging = true;

        readonly Dictionary<byte, ChartGroup> _chartGroups = new Dictionary<byte, ChartGroup>();
        private DeployView _embededDeployView;

        public ChartView()
        {
            InitializeComponent();

            LoadMiscPanel();

            _chartsContainer.DefaultControl = new ChartGroup { Text = "请选择通道" };

            _channelSelector.ChannelSelectionChanged += OnChannelSelectionChanged;
            _channelSelector.LoadChannelNamesFromConfig();

            _replayController = new ReplayController(_replayTimer, action => BeginInvoke(action));
            _replayController.PlayStateChanged += OnReplayControllerPlayStateChanged;
            _replayController.NewFrames += OnReplayControllerNewFrames;

            _realtimeController = new RealtimeController();
            _realtimeController.NewFrames += OnRealtimeControllerNewFrames;

            _hourPicker.Items.AddRange(Enumerable.Range(0, 24)
                .Select(i => (object)string.Format("{0:D2}:00", i)).ToArray());
            _hourPicker.SelectedIndex = 0;

            new CheckButtonGroup { _realtimeButton, _replayButton };
            _realtimeButton.Checked = true;
            OnRealtimeButtonCheckedChanged(_realtimeButton, EventArgs.Empty);

            RefreshDaysWithData();
            NewHourEvent.Instance.Register(t => this.BeginInvoke(RefreshDaysWithData));

            _realtimeTimer.Start();
            OnPlayStateChanged(PlayState.Play);
        }

        #region Realtime Logic

        private void OnRealtimeControllerNewFrames(object sender, NewFramesEventArgs e)
        {
            if(_currentViewMode == ViewMode.Realtime && e.ChannelFrames.Any())
            {
                this.BeginInvoke(() => ShowFrameSets(e.ChannelFrames));
            }
        }

        private void OnRealtimeButtonCheckedChanged(object sender, EventArgs e)
        {
            _currentViewMode = ViewMode.Realtime;
            EnableReplayControls(false);
        }

        private void OnRealtimeTimerTick(object sender, EventArgs e)
        {
            if(_currentViewMode == ViewMode.Realtime)
            {
                _realtimeController.Update();
            }
        }

        #endregion

        #region Common

        private void ShowFrameSets(IEnumerable<Tuple<byte, FrameSet>> channelFrames)
        {
            foreach(var channelFrame in channelFrames)
            {
                try
                {
                    _chartGroups[channelFrame.Item1].Set(channelFrame.Item2.Data);
                }
                catch(KeyNotFoundException)
                {
                    // Ignore
                }
            }
        }

        private void OnChannelSelectionChanged(object sender, ChannelSelectionChangedEventArgs e)
        {
            byte channelId = e.Channel;
            if(e.IsAdded)
            {
                var chartGroup = new ChartGroup()
                {
                    Dock = DockStyle.Fill,
                    Text = ChannelSelector.GetChannelName(channelId)
                };
                _chartsContainer.AddControl(chartGroup);
                _chartGroups.Add(channelId, chartGroup);
                _realtimeController.Channels.Add(channelId);

                SetReplaySelection(_channelSelector.SelectedChannels);
            }
            else
            {
                var chartGroup = _chartGroups[channelId];
                _chartsContainer.RemoveControl(chartGroup);
                chartGroup.Dispose();
                _chartGroups.Remove(channelId);
                _realtimeController.Channels.Remove(channelId);

                SetReplaySelection(_channelSelector.SelectedChannels);
            }
        }

        private void _playPauseButton_Click(object sender, EventArgs e)
        {
            switch(_currentViewMode)
            {
                case ViewMode.Realtime:
                    if (_realtimeTimer.Enabled)
                    {
                        _realtimeTimer.Stop();
                        OnPlayStateChanged(PlayState.Pause);
                    }
                    else
                    {
                        _realtimeTimer.Start();
                        OnPlayStateChanged(PlayState.Play);
                    }
                    break;
                case ViewMode.Replay:
                    _replayController.PlayPause();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        private void OnPlayStateChanged(PlayState newPlayState)
        {
            switch(newPlayState)
            {
                case PlayState.Play:
                    _playPauseButton.Image = Properties.Resources.Pause_icon32;
                    _playPauseButton.Text = "暂停";
                    break;
                case PlayState.Pause:
                    _playPauseButton.Image = Properties.Resources.Play_icon32;
                    _playPauseButton.Text = "播放";
                    break;
                default:
                    throw new ArgumentOutOfRangeException("newPlayState");
            }
        }

        private void EnableReplayControls(bool toEnable)
        {
            foreach(var control in
                new Control[] { _datePicker, _hourPicker, _fastButton, _slowButton, _slider })
            {
                control.Enabled = toEnable;
            }

            // TODO: dup?
            //            if(!toEnable)
            //                _playPauseButton.Image = Properties.Resources.Play_icon32;

            _replayController.Pause();

            if(toEnable)
            {
                OnPlayStateChanged(PlayState.Pause);
            }
            else
            {
                OnPlayStateChanged(PlayState.Play);
            }
        }

        #endregion


        #region Replay Logic

        private void OnReplayControllerNewFrames(object sender, NewFramesEventArgs e)
        {
            if(_currentViewMode == ViewMode.Replay && e.ChannelFrames.Any())
            {
                this.BeginInvoke(() =>
                {
                    var timestamp = e.ChannelFrames.First().Item2.StartTime;
                    _isUserChanging = false;
                    _datePicker.SelectionStart = timestamp.Date;
                    _hourPicker.SelectedIndex = timestamp.Hour;
                    _slider.Value = timestamp.Minute * 60 + timestamp.Second;
                    _isUserChanging = true;
                    ShowFrameSets(e.ChannelFrames);
                });
            }
        }

        private void OnReplayControllerPlayStateChanged(object sender, EventArgs<PlayState> e)
        {
            if (InvokeRequired)
            {
                this.BeginInvoke(() => OnPlayStateChanged(e.Data));
            }
            else
            {
                OnPlayStateChanged(e.Data);
            }
        }

        public void RefreshDaysWithData()
        {
            _datePicker.BoldedDates = _frameSource.DaysWithData;
            _datePicker.UpdateBoldedDates();
        }

        public void SetReplaySelection(IEnumerable<byte> channels)
        {
            _replayController.SetStartSegment(
                channels.ToArray(),
                _datePicker.SelectionStart,
                _hourPicker.SelectedIndex);
        }

        private void OnReplayButtonCheckedChanged(object sender, EventArgs e)
        {
            _currentViewMode = ViewMode.Replay;
            EnableReplayControls(true);
        }

        private void OnDatePickerDateSelected(object sender, DateRangeEventArgs e)
        {
            if(_isUserChanging)
            {
                SetReplaySelection(_channelSelector.SelectedChannels);
            }
        }

        private void OnHourPickerSelectedValueChanged(object sender, EventArgs e)
        {
            if(_isUserChanging)
            {
                SetReplaySelection(_channelSelector.SelectedChannels);
            }
        }

        private void OnSliderValueChanged(object sender, EventArgs e)
        {
            _labCurTick.Text = _slider.Value.ToString();
            if(_isUserChanging)
            {
                // TODO: Seek
            }
        }

        private void _fastButton_Click(object sender, EventArgs e)
        {
            _replayController.SpeedUp();
        }

        private void _slowButton_Click(object sender, EventArgs e)
        {
            _replayController.SlowDown();
        }

        #endregion

        #region Misc

        private void LoadMiscPanel()
        {
            _embededDeployView = new DeployView
            {
                HitTest = false,
                Parent = miscPanel,
                Dock = DockStyle.Fill
            };
        }

        #endregion


        #region Nested type: ViewMode

        private enum ViewMode
        {
            Realtime,
            Replay
        }

        #endregion
    }
}